package entity_model.json.deserializers;

import com.google.gson.*;
import entity_model.Attribute;
import entity_model.Entity;
import entity_model.EntityModel;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* Created by nuno-rafael-figueiredo on 13-05-2014.
*/
public class EntityDeserializer implements JsonDeserializer<Entity> {
    private final ThreadLocal<Map<String, Entity>> cache = new ThreadLocal<Map<String, Entity>>() {
        @Override
        protected Map<String, Entity> initialValue() {
            return new LinkedHashMap<>();
        }
    };

    @Override
    public Entity deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        EntityModel entityModel = EntityModelDeserializer.get(context);

        if (json.isJsonPrimitive())
            return getOrCreate(entityModel, json.getAsJsonPrimitive().getAsString());

        final JsonObject jsonObject = json.getAsJsonObject();

        // name
        Entity entity = getOrCreate(entityModel, jsonObject.get("name").getAsString());

        // anAbstract
        JsonElement anAbstractElement = jsonObject.get("abstract");
        if (anAbstractElement != null && anAbstractElement.getAsBoolean())
            entity.setAbstract();

        // attributes
        final JsonElement attributes = jsonObject.get("attributes");
        if (attributes != null)
            Collections.addAll(entity.getAttributes(), context.<Attribute[]>deserialize(attributes, Attribute[].class));

        // base
        final JsonElement base = jsonObject.get("base");
        if (base != null)
            entity.setBaseEntity(context.deserialize(base, Entity.class));

        return entity;
    }

    private Entity getOrCreate(EntityModel entityModel, String name) {
        Entity entity = cache.get().get(name);
        if (entity == null) {
            entity = new Entity(entityModel, name);
            cache.get().put(name, entity);
        }
        return entity;
    }
}
